package io.mft.yapi.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import cn.hutool.core.util.ObjectUtil;
import io.mft.api.domain.Api;
import io.mft.api.domain.ApiFunctionType;
import io.mft.api.domain.ApiRegulation;
import io.mft.api.domain.InputParameter;
import io.mft.api.domain.Output;
import io.mft.api.domain.OutputDs;
import io.mft.api.domain.OutputParameter;
import io.mft.api.domain.Regulation;
import io.mft.api.domain.RegulationProcessClassify;
import io.mft.commons.exception.MFTException;
import io.mft.dev.base.MFTRuntimeConfig;
import io.mft.dev.base.MFTRuntimeConfigProvider;
public class YApiMetaParser{

	

	public static YApiFunctionMeta parse(Api api) {
		//YApiFunction yApiFunction=classType.getDeclaredAnnotation(YApiFunction.class);
		if (api!=null) {
			YApiFunctionMeta yApiFunctionMeta=new YApiFunctionMeta();
			int funcNo=Integer.valueOf(api.getKey());
			String note=api.getName();
			yApiFunctionMeta.funcNo=funcNo;
			yApiFunctionMeta.note=note;
			yApiFunctionMeta.interfaceName=note;
			yApiFunctionMeta.categoryName=api.getModule().getName();
			yApiFunctionMeta.inYApiAttributeMetas=parseInputParameterField(api);
			yApiFunctionMeta.outYApiAttributeMetasMap.putAll(parseOutputParameterField(api));
			yApiFunctionMeta.setSystemKey(api.getModule().getSystem().getKey());
			return yApiFunctionMeta;
		}else {
			throw new MFTException("解析YApi元数据异常");
		}
	}
	
	public static class YApiFunctionMeta{
		 int funcNo;
		 String note;
		 String categoryName;  //分类名称
		 String interfaceName;//接口名称
		 String systemKey;
		 List<YApiAttributeMeta> inYApiAttributeMetas=new ArrayList<>();  //
		 Map<String, List<YApiAttributeMeta>>  outYApiAttributeMetasMap=new HashMap<String, List<YApiAttributeMeta>>();

		public int getFuncNo() {
			return funcNo;
		}

		public void setFuncNo(int funcNo) {
			this.funcNo = funcNo;
		}

		public String getNote() {
			return note;
		}

		public void setNote(String note) {
			this.note = note;
		}

		public String getCategoryName() {
			return categoryName;
		}

		public void setCategoryName(String categoryName) {
			this.categoryName = categoryName;
		}

		public String getInterfaceName() {
			return interfaceName;
		}

		public void setInterfaceName(String interfaceName) {
			this.interfaceName = interfaceName;
		}

		public List<YApiAttributeMeta> getInYApiAttributeMetas() {
			return inYApiAttributeMetas;
		}

		public void setInYApiAttributeMetas(List<YApiAttributeMeta> inYApiAttributeMetas) {
			this.inYApiAttributeMetas = inYApiAttributeMetas;
		}

		public Map<String, List<YApiAttributeMeta>> getOutYApiAttributeMetasMap() {
			return outYApiAttributeMetasMap;
		}

		public void setOutYApiAttributeMetasMap(Map<String, List<YApiAttributeMeta>> outYApiAttributeMetasMap) {
			this.outYApiAttributeMetasMap = outYApiAttributeMetasMap;
		}
		public void setSystemKey(String systemKey) {
			this.systemKey = systemKey;
		}
		public String getSystemKey() {
			return systemKey;
		}
	}
	
	public static class YApiAttributeMeta{

		 String note;  //参数描述或备注
		 boolean requried;//是否为必须参数 0--否，1--是
		 String name;    //参数名称
		 String example; //参数实例

		public YApiAttributeMeta(String note, boolean requried, String name, String example){
			this.note = note;
			this.requried = requried;
			this.name = name;
			this.example = example;
		}
        public YApiAttributeMeta(){}

		public String getNote() {
			return note;
		}

		public void setNote(String note) {
			this.note = note;
		}

		public boolean isRequried() {
			return requried;
		}

		public void setRequried(boolean requried) {
			this.requried = requried;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public String getExample() {
			return example;
		}

		public void setExample(String example) {
			this.example = example;
		}
	}
	static private List<YApiAttributeMeta> parseInputParameterField(Api api) {
		if (api.getApiFunctionType()==ApiFunctionType.combination) {
			if (api.getInput().getInputParameters().size()>0) {
				return parseProcessExecutorInputParameterField(api);
			}else {
				return parseCombinationInputParameterField(api);
			}
		}else {
			return parseProcessExecutorInputParameterField(api);
		}
	}
	
	private static List<YApiAttributeMeta> parseCombinationInputParameterField(Api api) {
		MFTRuntimeConfig config=MFTRuntimeConfigProvider.instance().provide();
		List<Api> apis=config.getApis();
		List<YApiAttributeMeta> yapiApiAttributeMetas=new ArrayList<>();
		List<ApiRegulation> apiRegulations=api.getApiRegulations();
		int k=0;
		for (ApiRegulation apiRegulation : apiRegulations) {
			Regulation regulation=apiRegulation.getRegulation();
			if (k>=1) {
				String chainConditionDriver=apiRegulations.get(0).getRegulation().getChainConditionDriver();
				if (!"noneDeliverReturn".equals(chainConditionDriver)) {
					break;
				}
			}
			String[] funcNos=regulation.getValue().split(",");
			for (int i = 0; i < funcNos.length; i++) {
				String funcNo=funcNos[i];
				Api fApi=null;
				 for (Api t : apis) {
						if (t.getKey().equals(funcNo)) {
							fApi=t;
							break;
						}
					}
				if (fApi.getApiFunctionType()==ApiFunctionType.processExecutor) {
					List<YApiAttributeMeta> funcNoYaApiAttributeMetas=parseProcessExecutorInputParameterField(fApi);
					yapiApiAttributeMetas.addAll(funcNoYaApiAttributeMetas);
				}else {
					List<YApiAttributeMeta> funcNoYaApiAttributeMetas=parseCombinationInputParameterField(fApi);
					yapiApiAttributeMetas.addAll(funcNoYaApiAttributeMetas);
				}
			}
			k++;
		}
		return yapiApiAttributeMetas;
	}
	private static List<YApiAttributeMeta> parseProcessExecutorInputParameterField(Api api) {
		List<YApiAttributeMeta> yapiApiAttributeMetas=new ArrayList<>();
		for (InputParameter inputParameter : api.getInput().getInputParameters()) {
			YApiAttributeMeta yaApiAttributeMeta=new YApiAttributeMeta();
			if (ObjectUtil.isNotEmpty(inputParameter.getRemark())) {
				yaApiAttributeMeta.note=inputParameter.getName()+","+inputParameter.getRemark();
			}else {
				yaApiAttributeMeta.note=inputParameter.getName();
			}
			
			yaApiAttributeMeta.name=inputParameter.getKey();
			yaApiAttributeMeta.requried=inputParameter.isRequire();
			yaApiAttributeMeta.example=inputParameter.getExample();
			yapiApiAttributeMetas.add(yaApiAttributeMeta);
		}
		return yapiApiAttributeMetas;
	}
	
	static private Map<String, List<YApiAttributeMeta>> parseOutputParameterField(Api api) {
		if (api.getApiFunctionType()==ApiFunctionType.combination) {
			if (api.getOutput().getOutputDsList().size()>0&&api.getOutput().getOutputDsList().get(0).getOutputParameters().size()>0) {
				return parseProcessExecutorOutputParameterField(api);
			}else {
				return parseCombinationOutputParameterField(api);
			}
		}else {
			return parseProcessExecutorOutputParameterField(api);
		}
	}
	
	
	
	static private Map<String, List<YApiAttributeMeta>> parseProcessExecutorOutputParameterField(Api api) {
		Output output = api.getOutput();
		Map<String, List<YApiAttributeMeta>> map = new HashMap<>();
		List<OutputDs> outputDsList = output.getOutputDsList();
		for (OutputDs outputDs : outputDsList) {
			List<YApiAttributeMeta> yapiApiAttributeMetas = new ArrayList<>();
			for (OutputParameter outputParameter : outputDs.getOutputParameters()) {
				YApiAttributeMeta yaApiAttributeMeta = new YApiAttributeMeta();
				if (ObjectUtil.isNotEmpty(outputParameter.getRemark())) {
					yaApiAttributeMeta.note=outputParameter.getName()+","+outputParameter.getRemark();
				}else {
					yaApiAttributeMeta.note=outputParameter.getName();
				}
				yaApiAttributeMeta.name = outputParameter.getKey();
				yaApiAttributeMeta.requried = false;
				yaApiAttributeMeta.example = outputParameter.getExample();
				yapiApiAttributeMetas.add(yaApiAttributeMeta);
			}
			map.put(outputDs.getDsKey(), yapiApiAttributeMetas);
			if (outputDs.isPage()) {
				List<YApiAttributeMeta> pageApiAttributeMetas = new ArrayList<>();
				String [] ps=new String[] {"totalRows","currentPage","numPerPage","data"};
				String [] pns=new String[] {"总行数","当前页码","每页条数","分页数据,见具体结果集"};
				String [] pes=new String[] {"","","",outputDs.getDsKey()};
				for (int i = 0; i < ps.length; i++) {
					YApiAttributeMeta yaApiAttributeMeta = new YApiAttributeMeta();
					yaApiAttributeMeta.note =pns[i];
					yaApiAttributeMeta.name = ps[i];
					yaApiAttributeMeta.requried = true;
					yaApiAttributeMeta.example = pes[i];
					pageApiAttributeMetas.add(yaApiAttributeMeta);
				}
				map.put(outputDs.getDsKey()+".page", pageApiAttributeMetas);
			}
		}
		return map;
	}
	static private Map<String, List<YApiAttributeMeta>> parseCombinationOutputParameterField(Api api) {
		MFTRuntimeConfig config=MFTRuntimeConfigProvider.instance().provide();
		List<Api> apis=config.getApis();
		Map<String, List<YApiAttributeMeta>> map = new HashMap<>();
		List<ApiRegulation> apiRegulations=api.getApiRegulations();
		int k=0;
		for (ApiRegulation apiRegulation : apiRegulations) {
			Regulation regulation=apiRegulation.getRegulation();
			if (regulation.getProcessClassify()==RegulationProcessClassify.async) {
				break;
			}
			String reqTag="";
			if (k-1>=0) {
				ApiRegulation last=apiRegulations.get(k-1);
				if ("iterateLoopSyncReturn".equals(last.getRegulation().getChainConditionDriver())) {
					if (regulation.getProcessClassify()==RegulationProcessClassify.syncWaitAsync) {
						reqTag="{reqTag}.";
					}
				}
			}

			String[] funcNos=regulation.getValue().split(",");
			for (int i = 0; i < funcNos.length; i++) {
				String funcNo=funcNos[i];
				Api fApi=null;
				 for (Api t : apis) {
						if (t.getKey().equals(funcNo)) {
							fApi=t;
							break;
						}
					}
				if (fApi.getApiFunctionType()==ApiFunctionType.processExecutor) {
					Map<String, List<YApiAttributeMeta>>  dsMap=parseProcessExecutorOutputParameterField(fApi);
					Set<String> keys=dsMap.keySet();
					for (String sk : keys) {
						String key=funcNo+"."+reqTag+sk;
						map.put(key,dsMap.get(sk));
					}
				}else {
					Map<String, List<YApiAttributeMeta>> dsMap=parseCombinationOutputParameterField(fApi);
					Set<String> keys=dsMap.keySet();
					for (String sk : keys) {
						String key=funcNo+"."+reqTag+sk;
						map.put(key,dsMap.get(sk));
					}
				}
			}
			k++;
		}
		return map;
	}
}
